
import java.util.logging.Level;
import java.util.logging.Logger;
import nanoxml.*;
import java.util.*;
import java.io.*;
import java.net.*;

/**
 * Define un servidor que espera comandos provenientes de un cliente, y en funcion de los
 * comando que recibe, le envia una respuesta al cliente.
 */
public class Nodo extends Thread {
    private ServerSocket server;
    private BufferedReader serverIn;
    private PrintWriter serverOut;
    private int portNumb = 10762;
    private String nombre;
    private List<String> conocidos;
    private String biblioteca;
    private List<Cancion> playlistActual;
    private int numCancion = 0;
    private Socket clientSocket;
    private String miIp;

public Nodo(int puerto, String biblioteca, String nombre,Socket clientSocket){

    this.portNumb = puerto;
    this.biblioteca = biblioteca;
    this.nombre = nombre;
    this.playlistActual = new ArrayList<Cancion>();
    this.clientSocket = clientSocket;

    // Canal de entrada de datso provenientes del cliente 
     this.serverIn = null;

    // Canal de salida de datos hacia el cliente 
     this.serverOut = null; 

    System.out.println("Servidor de Prueba en Java, activado!" );
  }


public void run(){

    try{
              
            // espera a que se conecte alg�n cliente a nuestro puerto
          System.out.println("Estado antes de aceptar:"+this.getServer());

         // Creacion de los canales de entrada y salida paracomunicarse con el cliente
          this.serverIn =  new BufferedReader(new InputStreamReader(clientSocket.getInputStream())); 
          this.serverOut = new PrintWriter(clientSocket.getOutputStream(), true); 

        // A partir de este punto un cliente ya se ha conectado al servidor
    //      System.out.println("Clientsocket despues de aceptar: " + clientSocket);


    // env�a la l�nea de identificaci�n inicial del servidor

       boolean quit = false;
	// �Qu� tiene que decirnos el cliente?
       while( ! quit ) {
        (this.serverOut).println("Servidor de Prueba en Java 1.2, " + new Date() );
	String clientRequest = this.serverIn.readLine();
        if (clientRequest.startsWith("c") || clientRequest.startsWith("C")){
         String[] linea = clientRequest.split("\t");
         this.miIp = linea[1].trim();         
         String[] param = linea[0].split(" ");
         List<Cancion> canciones = new ArrayList<Cancion>();
         try {
            this.obtenerBiblioteca(this.playlistActual, biblioteca);
         } catch (Exception ex) {
            Logger.getLogger(Nodo.class.getName()).log(Level.SEVERE, null, ex);
         }
         if (param.length < 3){
             System.err.print("Cantidad de parametros invalidas para realizar consulta");
             break;
         }
         else if (param.length >= 4){
             
             String consulta = "";
             for (int i = 2; i<param.length; i++){
              consulta = consulta + param[i] + " ";
             }
              param[2] = consulta.trim();
              System.out.println(param[2]);
         }
        if (param[1].compareToIgnoreCase("-a") == 0){
           canciones = this.buscarCancionPorAutor(param[2]);
        
        }
        else if (param[1].compareToIgnoreCase("-t") == 0){
           canciones = this.buscarCancionPorTitulo(param[2]); 
        }
        else{
            System.err.print("Parametros invalidos para realizar consulta.");
            break;
        }
        if (canciones.isEmpty()){
            
            this.serverOut.println("corte");
        }
        else{
        (this.serverOut).println(toStringListaCanciones(canciones)+"corte");
	System.out.println("El cliente me dice: "+clientRequest);
        }
         this.playlistActual.clear();
         }
        else if (clientRequest.equalsIgnoreCase("q")){
            quit = true;
        }
        System.out.println("Fin loopp \n");
        }
        System.out.println("Server says: Bye \n");
        }
         catch (IOException e) {
         System.out.println("Excepcion E/S en server.in.readLine() " + e);
         }
    
        
	
}

public static void main(String[] args) {

    if (args.length < 8){
     System.err.print("Error: Numero invalido de parametros");
    }
    
    int puerto = Integer.parseInt(args[1]);
    String archConocidos = args[3];
    String biblioteca = args[5];
    String nombreNodo = args[7];
    try {
    ServerSocket server = new ServerSocket(puerto);
    while(true){
                Nodo nodoServer = new Nodo(puerto,biblioteca,nombreNodo,server.accept());
                nodoServer.setConocidos(nodoServer.extraerConocidos(archConocidos));
                nodoServer.start();
    }
    } catch (IOException ex) {
                Logger.getLogger(Nodo.class.getName()).log(Level.SEVERE, null, ex);
    }
    
} // End of main method.

public List<Cancion> buscarCancionPorTitulo(String titulo){
   List<Cancion> cancionesTitulo = new ArrayList<Cancion>();
    for (int i= 0; i<this.playlistActual.size(); i++ ){
        if (this.playlistActual.get(i).getTitle().compareToIgnoreCase(titulo) == 0){
            cancionesTitulo.add(this.playlistActual.get(i));
        }
   }
    
    return cancionesTitulo; 
}

public List<Cancion> buscarCancionPorAutor(String autor){
   List<Cancion> cancionesAutor = new ArrayList<Cancion>();
    for (int i= 0; i<this.playlistActual.size(); i++ ){
        if (this.playlistActual.get(i).getCreator().compareToIgnoreCase(autor) == 0){
            cancionesAutor.add(this.playlistActual.get(i));
        }
   }
    
    return cancionesAutor; 
}

public static String toStringListaCanciones (List<Cancion> canciones){
    String s = "";    
    for(int i= 0; i<canciones.size(); i++){
	 String c = canciones.get(i).toString();
	  s = s + c;
         }
    return s;

}

public List<String> extraerConocidos(String archConocidos){
   BufferedReader bufin;
   List<String> listaConocidos = new ArrayList<String>();
        try{

          bufin = new BufferedReader(new FileReader(archConocidos));			
           try{
            String linea = bufin.readLine();
            while (linea != null){ 
               listaConocidos.add(linea);
               linea = bufin.readLine();
            }
           } catch (Exception ioe){
                 System.err.println("Error Abriendo el archivo");
             }
        } catch (FileNotFoundException fnfe){
          System.err.println("No se encontro el archivo");
        }
    
return listaConocidos;
}

public void obtenerBiblioteca(List<Cancion> playlist, String biblioteca)
      throws Exception {
	    FileReader reader = new FileReader(biblioteca);
	    XMLElement xml = new XMLElement();
	    xml.parseFromReader(reader);
		
		Enumeration enumChild = xml.enumerateChildren();
	    XMLElement xml1 = (XMLElement)enumChild.nextElement(); //Tracklist

		 // System.out.println("ELEMENTO"+xml1+"\n"); 
		  int grandChildNumber = xml1.countChildren();
		  Enumeration enumGchild = xml1.enumerateChildren();
		  
            for (int j= 0; j<grandChildNumber; j++){  // Estos son los tracks
		   XMLElement xml2 = (XMLElement) enumGchild.nextElement();
		 //  System.out.println("EL NIETO"+xml2);
		   Enumeration tracks = xml2.enumerateChildren();
		   String localiz = null;
		   String title = null;
		   String creator = null;
		   XMLElement xml3 = (XMLElement)tracks.nextElement();
		  while(localiz == null || title ==null || creator ==null){ 

			if (xml3.getName().compareTo("location") == 0){
			localiz = xml3.getContent();
			System.out.println(localiz);
			}
			else if (xml3.getName().compareTo("title") == 0){
		    title = xml3.getContent();
			System.out.println(title);
			}
			else if (xml3.getName().compareTo("creator") == 0){
			creator = xml3.getContent();
			System.out.println(creator);
			}
			xml3 = (XMLElement)tracks.nextElement();
		  }
                  Cancion cancion = new Cancion(this.numCancion++,title,creator,localiz,this.nombre,this.miIp);
                  playlist.add(cancion);
		
		}
	  }

//GETTERS

    public String getBiblioteca() {
        return biblioteca;
    }

    public List<String> getConocidos() {
        return conocidos;
    }

    public String getNombre() {
        return nombre;
    }

    public int getPortNumb() {
        return portNumb;
    }

    public ServerSocket getServer() {
        return server;
    }

    public BufferedReader getServerIn() {
        return serverIn;
    }

    public PrintWriter getServerOut() {
        return serverOut;
    }

    public List<Cancion> getPlaylistActual() {
        return playlistActual;
    }
    

//SETTERS
    public void setBiblioteca(String biblioteca) {
        this.biblioteca = biblioteca;
    }

    public void setConocidos(List<String> conocidos) {
        this.conocidos = conocidos;
    }

    public void setServerIn(BufferedReader in) {
        this.serverIn = in;
    }

    public void setNombre(String nombre) {
        this.nombre = nombre;
    }

    public void setServerOut(PrintWriter out) {
        this.serverOut = out;
    }

    public void setPortNumb(int portNumb) {
        this.portNumb = portNumb;
    }

    public void setServer(ServerSocket server) {
        this.server = server;
    }

    public void setPlaylistActual(List<Cancion> playlistActual) {
        this.playlistActual = playlistActual;
    }
 

} // End of ServerTest class. 
